package com.example.billin.opengltest.shader.render

import android.content.Context
import android.graphics.Color
import android.opengl.Matrix
import android.util.Log
import com.example.billin.opengltest.BuildConfig
import com.example.billin.opengltest.shader.program.RightAngleRectColorProgram
import com.example.billin.opengltest.shader.program.RoundPointDisperseProgram
import com.example.billin.opengltest.shader.program.apply
import com.example.billin.opengltest.shader.program.draw
import com.example.billin.opengltest.visualizer.PiecewiseFormula
import com.example.billin.opengltest.visualizer.VisualizerCalculateUtil
import com.example.billin.opengltest.visualizer.VisualizerRender
import java.util.*

class LittleBallRectColorRender(val context: Context) : VisualizerRender() {

    private val BALL_MAX_WIDTH = 120

    private val CYLINDER_WIDTH = 100

    private val LIGHT_LENGTH_ADDICTION = 200f

    // 1.6 月球的重力; 9.8 地球的重力
    private val GRAVITY = 0.0016f

    /**
     * 需要的数据大小
     */
    private val DATA_LENGTH = 110

    //粒子数量
    private val POINT_LENGTH = 20
    private val POINT_MAX_SIZE = 20

    private val projectMatrix: FloatArray = FloatArray(16)
    private val viewMatrix: FloatArray = FloatArray(16)
    private val viewProjectMatrix: FloatArray = FloatArray(16)






    //圆柱
    private val cylinderData: FloatArray = FloatArray(DATA_LENGTH * 4)

    private val triangleData: FloatArray = FloatArray(DATA_LENGTH * 4)

    private val ballData: FloatArray = FloatArray(DATA_LENGTH * 2)
    //球速率
    private val ballVelocity: FloatArray = FloatArray(DATA_LENGTH)

    private var mPointList: MutableList<DispersePoint>? = null


    private var lastDrawTime: Long = 0

    private var centerX = 0f

    private var centerY = 0f

    private var innerWidth = 0f

    private var size = 0f





    //绘制线
    private lateinit var rightAngleRectColorProgram: RightAngleRectColorProgram
    //绘制点
    private lateinit var roundPointDisperseProgram: RoundPointDisperseProgram





    override fun processData(rawData: FloatArray?, length: Int): Int {
        val cropLength = (length - DATA_LENGTH * 2) / 2
        VisualizerCalculateUtil.cropOriginFftData(
            rawData,
            cropLength,
            cropLength,
            length
        )
        VisualizerCalculateUtil.processFftMagnitudeData(
            rawData,
            DATA_LENGTH * 2
        )
        VisualizerCalculateUtil.flatData(
            rawData, PiecewiseFormula(
                Math.hypot(128.0, 128.0).toFloat(),
                CYLINDER_WIDTH.toFloat(), 10f, 10f
            ), DATA_LENGTH
        )

        return DATA_LENGTH
    }

    private companion object {
        private const val TAG = "RectColorRender"
    }

    private val timeArray = LongArray(60)
    private var timeIndex = 0

    override fun draw(processedData: FloatArray?) {
        processedData ?: return
                    //radius=屏幕宽度的2/3
        val radius = innerWidth / 2

        //绘制当前帧的时间
        val currentDrawTime = System.currentTimeMillis()
        //间隔时间
        val intervalTime = currentDrawTime - lastDrawTime

        if (BuildConfig.DEBUG) {
            timeArray[timeIndex] = intervalTime
            timeIndex = (timeIndex + 1) % timeArray.size
            if (timeIndex == 0) Log.d(TAG, "draw: ${1000.0 / timeArray.average()}")
        }

        lastDrawTime = currentDrawTime



        for (i in 0 until POINT_LENGTH){
            var dispersePoint: DispersePoint? = mPointList?.get(i)
            if (dispersePoint != null) {
                if(dispersePoint.distance>200){
                    //每次>200的话重新随机一个粒子
                    //任意角度和距离
                    dispersePoint.distance= 0F
                }
                dispersePoint.distance+=intervalTime*0.1f
            }

        }


        for (i in 0 until DATA_LENGTH) {
            val degree = i.toDouble() / DATA_LENGTH * 2.0 * Math.PI
            val cosDegree = Math.cos(degree)
            var sinDegree = Math.sin(degree)

            val ci = i * 4
            //processedData是音频数据的一个值
            val endRadius = radius + processedData[i]
            val preEndRadius =
                if (sinDegree == 0.0) cylinderData[ci + 3]
                else (cylinderData[ci + 2] / sinDegree).toFloat()

            //这里是前后两个点:inner(x,y)   out(x,y)
            cylinderData[ci] = (sinDegree * radius).toFloat()
            cylinderData[ci + 1] = (cosDegree * radius).toFloat()
            cylinderData[ci + 2] = (sinDegree * (endRadius)).toFloat()
            cylinderData[ci + 3] = (cosDegree * (endRadius)).toFloat()

            //这里是前后两个点:inner(x,y)   out(x,y)
            triangleData[ci] = (sinDegree * radius).toFloat()
            triangleData[ci + 1] = (cosDegree * radius).toFloat()
            triangleData[ci + 2] = (sinDegree * (endRadius+50)).toFloat()
            triangleData[ci + 3] = (cosDegree * (endRadius+50)).toFloat()


            val bi = i * 2
            val ballVelocityI = bi / 2

            val ballRadius =
                if (sinDegree == 0.0) ballData[bi + 1]
                else (ballData[bi] / sinDegree).toFloat()

            if (ballRadius > endRadius) {
                // 球的半径比柱体大，根据重力改变球的速度
                val newBallRadius: Float = ballRadius +
                        ballVelocity[ballVelocityI] * intervalTime -
                        GRAVITY * intervalTime.toFloat() * intervalTime.toFloat() / 2f

                // 超出限高，强制速度为 0
                if (newBallRadius > BALL_MAX_WIDTH + radius) {
                    ballData[bi] = ((BALL_MAX_WIDTH + radius) * sinDegree).toFloat()
                    ballData[bi + 1] = ((BALL_MAX_WIDTH + radius) * cosDegree).toFloat()
                    ballVelocity[ballVelocityI] = 0f
                } else {
                    ballData[bi] = (newBallRadius * sinDegree).toFloat()
                    ballData[bi + 1] = (newBallRadius * cosDegree).toFloat()
                    ballVelocity[ballVelocityI] = ballVelocity[ballVelocityI] - GRAVITY * intervalTime
                }
            } else {
                // 球的半径比柱体小，根据动量守恒和能量守恒改变球的速度(柱体的重量假设为无限大，球的重量为 1)
                val v = 2f * (endRadius - preEndRadius) / intervalTime
                if (v > ballVelocity[ballVelocityI]) ballVelocity[ballVelocityI] = v

                ballData[bi] = cylinderData[ci + 2]
                ballData[bi + 1] = cylinderData[ci + 3]
            }
        }




        roundPointDisperseProgram.draw {
            bindPositions(mPointList, mPointList!!.size)
        }


        rightAngleRectColorProgram.draw {
            bindLines(triangleData, triangleData.size)
        }
    }

    override fun onResize(width: Float, height: Float) {
        centerX = width / 2
        centerY = height / 2

        this.size = Math.min(width, height)
        this.innerWidth = width * 2 / 3

        initDispersePoint(POINT_LENGTH)

        Matrix.orthoM(
            projectMatrix, 0, 0f, width,
            height, 0f, -1f, 1f
        )
        Matrix.setIdentityM(viewMatrix, 0)
        Matrix.translateM(viewMatrix, 0, centerX, centerY, 0f)
        Matrix.multiplyMM(viewProjectMatrix, 0, projectMatrix, 0, viewMatrix, 0)

        roundPointDisperseProgram.apply {
            setMatrix(viewProjectMatrix)
            setScreenSize(width.toInt(), height.toInt())
            setColor(Color.parseColor("#FF0000FF"))
        }

        rightAngleRectColorProgram.apply {
            setMatrix(viewProjectMatrix)
            setSize(10)
            setAntialias(1f)
            setColor(Color.parseColor("#37A1FA"))
        }
    }

    private fun initDispersePoint(pointNum:Int) {
        mPointList= mutableListOf()
        for(i in 0 until pointNum){
            val nextInt = Random().nextInt(10)
            val degree = i.toDouble() / pointNum * 2.0 * Math.PI
            val radius = innerWidth / 2

            mPointList!!.add(i,DispersePoint(POINT_MAX_SIZE-10+nextInt, degree.toFloat(),radius))
        }
    }

    override fun surfaceCreated() {
        rightAngleRectColorProgram = RightAngleRectColorProgram(context)
        roundPointDisperseProgram = RoundPointDisperseProgram(context)
    }

    open class DispersePoint(pointSize:Int,pointAngle:Float,radius:Float){
        var size=pointSize
        var distance=0f
        var agele=pointAngle
        var radius=radius
    }
}